package com.william.jdbcplus.core.dialects.ddl.table.impl;

import com.william.jdbcplus.core.metadata.*;
import com.william.jdbcplus.common.entity.Entity;
import com.william.jdbcplus.core.dialects.ddl.table.ITable;
import com.william.jdbcplus.core.toolkit.StringPool;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public class OracleTable implements ITable {
    /**
     * 创建表
     *
     * @param clazz
     * @return
     */
    @Override
    public <M extends Entity> String create(Class<M> clazz) {
        TableInfo tableInfo = TableHelperUtil.getTableInfo(clazz);
        List<TableColumnInfo> fieldList = tableInfo.getColumnList();
        StringBuffer sql = new StringBuffer();
        sql.append(StringPool.NEWLINE + "create table" + StringPool.SPACE + tableInfo.getTableName() + StringPool.SPACE + "(")
                .append(StringPool.NEWLINE + tableInfo.getKeyColumn() + StringPool.SPACE + convertToKeyColumn(tableInfo.getKeyType(), tableInfo.getKeySize()))
                .append(" not null ");
        for (TableColumnInfo fieldInfo : fieldList) {
            sql
                    .append(StringPool.COMMA + StringPool.NEWLINE)
                    .append(fieldInfo.getColumn() + StringPool.SPACE + convertToSqlColumn(fieldInfo))
                    .append(fieldInfo.isNullable() ? " null " : " not null ");
        }
        sql.append(StringPool.NEWLINE + ");");
        sql.append(StringPool.NEWLINE + "comment on table " + tableInfo.getTableName() + " is '" + tableInfo.getTableRemarks().replace(';', ' ') + "';");
        for (TableColumnInfo fieldInfo : fieldList) {
            sql.append(StringPool.NEWLINE + "comment on column " + tableInfo.getTableName() + StringPool.DOT + fieldInfo.getColumn() + " is '" + fieldInfo.getRemarks().replace(';', ' ') + "';");
        }

        // 生成主键
        if (tableInfo.getPkList().size() > 0) {
            TablePkInfo pkInfo = tableInfo.getPkList().get(0);
            sql.append(StringPool.NEWLINE + "alter table " + tableInfo.getTableName() + " add constraint " + pkInfo.getShortPkName() + " primary key(" + pkInfo.getPkColumn() + ");");
        }

        List<TableUkInfo> uniqueList = tableInfo.getUkList();
        for (TableUkInfo unique : uniqueList) {
            String columnNames = unique.getColumns().stream().collect(Collectors.joining(StringPool.COMMA));
            String uniqueName = unique.getShortUkName();
            sql.append(StringPool.NEWLINE).append("alter table " + tableInfo.getTableName() + " add constraint  " + uniqueName + " unique (" + columnNames + ");");
        }

        List<TableIndexInfo> indexList = tableInfo.getIndexList();
        for (TableIndexInfo index : indexList) {
            String columnNames = index.getColumns().stream().collect(Collectors.joining(StringPool.COMMA));
            String indexName = index.getShortIndexName();
            if (!index.isUnique()) {
                sql.append(StringPool.NEWLINE).append("create index " + indexName + " on " + tableInfo.getTableName() + " (" + columnNames + ");");
            } else {
                sql.append(StringPool.NEWLINE).append("create unique index " + indexName + " on " + tableInfo.getTableName() + " (" + columnNames + ");");
            }
        }

        List<TableFkInfo> fkList = tableInfo.getFkList();
        for (TableFkInfo fk : fkList) {
            // 先执行外键唯一键索引
            // sql.append(StringPool.NEWLINE).append("alter table " + fk.getPkTableName() + " add constraint  " + fk.getPkShortColumnUkName() + " unique (" + fk.getPkColumnName() + ");");
            //alter table 从表 add constraint 外键名（形如：FK_从表_主表） foreign key (从表外键字段) references 主表(主键字段);
            sql.append(StringPool.NEWLINE).append("alter table " + tableInfo.getTableName() + " add constraint " + fk.getShortFkName() + " foreign key (" + fk.getFkColumnName()
                    + ") references " + fk.getPkTableName() + "(" + fk.getPkColumnName() + ");");
        }

        String sqlText = sql.toString();
        return sqlText;
    }

    public String convertToSqlColumn(TableColumnInfo fieldInfo) {
        Class<?> javaClass = fieldInfo.getPropertyType();
        String decimalDigits = fieldInfo.getDigits() > 0 ? "," + fieldInfo.getDigits() : "";
        int length = fieldInfo.getSize();
        if (Boolean.class.equals(javaClass) || javaClass.getName().equals("boolean")) {
            if (length > 38) {
                length = 1;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (Short.class.equals(javaClass) || javaClass.getName().equals("short")) {
            if (length > 38) {
                length = 4;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (Integer.class.equals(javaClass) || javaClass.getName().equals("int")) {
            if (length > 38) {
                length = 10;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (Long.class.equals(javaClass) || javaClass.getName().equals("long")) {
            if (length > 38) {
                length = 20;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (BigInteger.class.equals(javaClass)) {
            if (length > 38) {
                length = 38;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (Float.class.equals(javaClass) || javaClass.getName().equals("float")) {
            if (length > 38) {
                length = 20;
            }
            return "number" + StringPool.LEFT_BRACKET + length + decimalDigits + StringPool.RIGHT_BRACKET;
        } else if (Double.class.equals(javaClass) || javaClass.getName().equals("double")) {
            if (length > 38) {
                length = 30;
            }
            return "number" + StringPool.LEFT_BRACKET + length + decimalDigits + StringPool.RIGHT_BRACKET;
        } else if (BigDecimal.class.equals(javaClass)) {
            if (length > 38) {
                length = 38;
            }
            return "number" + StringPool.LEFT_BRACKET + length + decimalDigits + StringPool.RIGHT_BRACKET;
        } else if (Date.class.equals(javaClass)) {
            return "date";
        } else if (String.class.equals(javaClass)) {
            if (length > 4000) {
                return "clob";
            } else {
                return "varchar2" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
            }
        }

        return "varchar2(50)";
    }

    public String convertToKeyColumn(Class<?> javaClass, int length) {
        if (Short.class.equals(javaClass) || javaClass.getName().equals("short")) {
            if (length > 38) {
                length = 4;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (Integer.class.equals(javaClass) || javaClass.getName().equals("int")) {
            if (length > 38) {
                length = 10;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (Long.class.equals(javaClass) || javaClass.getName().equals("long")) {
            if (length > 38) {
                length = 20;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (BigInteger.class.equals(javaClass)) {
            if (length > 38) {
                length = 38;
            }
            return "number" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        } else if (String.class.equals(javaClass)) {
            if (length > 4000) {
                length = 4000;
            }
            return "varchar2" + StringPool.LEFT_BRACKET + length + StringPool.RIGHT_BRACKET;
        }

        return "varchar2(50)";
    }
}
